import { Extension, textInputRule } from "@tiptap/core"

export interface TypographyOptions {
  /**
   * The em dash character.
   * @default '—'
   */
  emDash: false | string

  /**
   * The ellipsis character.
   * @default '…'
   */
  ellipsis: false | string

  /**
   * The open double quote character.
   * @default '“'
   */
  openDoubleQuote: false | string

  /**
   * The close double quote character.
   * @default '”'
   */
  closeDoubleQuote: false | string

  /**
   * The open single quote character.
   * @default '‘'
   */
  openSingleQuote: false | string

  /**
   * The close single quote character.
   * @default '’'
   */
  closeSingleQuote: false | string

  /**
   * The left arrow character.
   * @default '←'
   */
  leftArrow: false | string

  /**
   * The right arrow character.
   * @default '→'
   */
  rightArrow: false | string

  /**
   * The copyright character.
   * @default '©'
   */
  copyright: false | string

  /**
   * The trademark character.
   * @default '™'
   */
  trademark: false | string

  /**
   * The servicemark character.
   * @default '℠'
   */
  servicemark: false | string

  /**
   * The registered trademark character.
   * @default '®'
   */
  registeredTrademark: false | string

  /**
   * The one half character.
   * @default '½'
   */
  oneHalf: false | string

  /**
   * The plus minus character.
   * @default '±'
   */
  plusMinus: false | string

  /**
   * The not equal character.
   * @default '≠'
   */
  notEqual: false | string

  /**
   * The laquo character.
   * @default '«'
   */
  laquo: false | string

  /**
   * The raquo character.
   * @default '»'
   */
  raquo: false | string

  /**
   * The multiplication character.
   * @default '×'
   */
  multiplication: false | string

  /**
   * The superscript two character.
   * @default '²'
   */
  superscriptTwo: false | string

  /**
   * The superscript three character.
   * @default '³'
   */
  superscriptThree: false | string

  /**
   * The one quarter character.
   * @default '¼'
   */
  oneQuarter: false | string

  /**
   * The three quarters character.
   * @default '¾'
   */
  threeQuarters: false | string
}

export const emDash = (override?: string) =>
  textInputRule({
    find: /--$/,
    replace: override ?? "—",
  })

export const ellipsis = (override?: string) =>
  textInputRule({
    find: /\.\.\.$/,
    replace: override ?? "…",
  })

export const openDoubleQuote = (override?: string) =>
  textInputRule({
    find: /(?:^|[\s{[(<'"\u2018\u201C])(")$/,
    replace: override ?? "“",
  })

export const closeDoubleQuote = (override?: string) =>
  textInputRule({
    find: /"$/,
    replace: override ?? "”",
  })

export const openSingleQuote = (override?: string) =>
  textInputRule({
    find: /(?:^|[\s{[(<'"\u2018\u201C])(')$/,
    replace: override ?? "‘",
  })

export const closeSingleQuote = (override?: string) =>
  textInputRule({
    find: /'$/,
    replace: override ?? "’",
  })

export const leftArrow = (override?: string) =>
  textInputRule({
    find: /<-$/,
    replace: override ?? "←",
  })

export const rightArrow = (override?: string) =>
  textInputRule({
    find: /->$/,
    replace: override ?? "→",
  })

export const copyright = (override?: string) =>
  textInputRule({
    find: /\(c\)$/,
    replace: override ?? "©",
  })

export const trademark = (override?: string) =>
  textInputRule({
    find: /\(tm\)$/,
    replace: override ?? "™",
  })

export const servicemark = (override?: string) =>
  textInputRule({
    find: /\(sm\)$/,
    replace: override ?? "℠",
  })

export const registeredTrademark = (override?: string) =>
  textInputRule({
    find: /\(r\)$/,
    replace: override ?? "®",
  })

export const oneHalf = (override?: string) =>
  textInputRule({
    find: /(?:^|\s)(1\/2)\s$/,
    replace: override ?? "½",
  })

export const plusMinus = (override?: string) =>
  textInputRule({
    find: /\+\/-$/,
    replace: override ?? "±",
  })

export const notEqual = (override?: string) =>
  textInputRule({
    find: /!=$/,
    replace: override ?? "≠",
  })

export const laquo = (override?: string) =>
  textInputRule({
    find: /<<$/,
    replace: override ?? "«",
  })

export const raquo = (override?: string) =>
  textInputRule({
    find: />>$/,
    replace: override ?? "»",
  })

export const multiplication = (override?: string) =>
  textInputRule({
    find: /\d+\s?([*x])\s?\d+$/,
    replace: override ?? "×",
  })

export const superscriptTwo = (override?: string) =>
  textInputRule({
    find: /\^2$/,
    replace: override ?? "²",
  })

export const superscriptThree = (override?: string) =>
  textInputRule({
    find: /\^3$/,
    replace: override ?? "³",
  })

export const oneQuarter = (override?: string) =>
  textInputRule({
    find: /(?:^|\s)(1\/4)\s$/,
    replace: override ?? "¼",
  })

export const threeQuarters = (override?: string) =>
  textInputRule({
    find: /(?:^|\s)(3\/4)\s$/,
    replace: override ?? "¾",
  })

/**
 * This extension allows you to add typography replacements for specific characters.
 * @see https://www.tiptap.dev/api/extensions/typography
 */
export const Typography = Extension.create<TypographyOptions>({
  name: "typography",

  addOptions() {
    return {
      closeDoubleQuote: "”",
      closeSingleQuote: "’",
      copyright: "©",
      ellipsis: "…",
      emDash: "—",
      laquo: "«",
      leftArrow: "←",
      multiplication: "×",
      notEqual: "≠",
      oneHalf: "½",
      oneQuarter: "¼",
      openDoubleQuote: "“",
      openSingleQuote: "‘",
      plusMinus: "±",
      raquo: "»",
      registeredTrademark: "®",
      rightArrow: "→",
      servicemark: "℠",
      superscriptThree: "³",
      superscriptTwo: "²",
      threeQuarters: "¾",
      trademark: "™",
    }
  },

  addInputRules() {
    const rules = []

    if (this.options.emDash !== false) {
      rules.push(emDash(this.options.emDash))
    }

    if (this.options.ellipsis !== false) {
      rules.push(ellipsis(this.options.ellipsis))
    }

    if (this.options.openDoubleQuote !== false) {
      rules.push(openDoubleQuote(this.options.openDoubleQuote))
    }

    if (this.options.closeDoubleQuote !== false) {
      rules.push(closeDoubleQuote(this.options.closeDoubleQuote))
    }

    if (this.options.openSingleQuote !== false) {
      rules.push(openSingleQuote(this.options.openSingleQuote))
    }

    if (this.options.closeSingleQuote !== false) {
      rules.push(closeSingleQuote(this.options.closeSingleQuote))
    }

    if (this.options.leftArrow !== false) {
      rules.push(leftArrow(this.options.leftArrow))
    }

    if (this.options.rightArrow !== false) {
      rules.push(rightArrow(this.options.rightArrow))
    }

    if (this.options.copyright !== false) {
      rules.push(copyright(this.options.copyright))
    }

    if (this.options.trademark !== false) {
      rules.push(trademark(this.options.trademark))
    }

    if (this.options.servicemark !== false) {
      rules.push(servicemark(this.options.servicemark))
    }

    if (this.options.registeredTrademark !== false) {
      rules.push(registeredTrademark(this.options.registeredTrademark))
    }

    if (this.options.oneHalf !== false) {
      rules.push(oneHalf(this.options.oneHalf))
    }

    if (this.options.plusMinus !== false) {
      rules.push(plusMinus(this.options.plusMinus))
    }

    if (this.options.notEqual !== false) {
      rules.push(notEqual(this.options.notEqual))
    }

    if (this.options.laquo !== false) {
      rules.push(laquo(this.options.laquo))
    }

    if (this.options.raquo !== false) {
      rules.push(raquo(this.options.raquo))
    }

    if (this.options.multiplication !== false) {
      rules.push(multiplication(this.options.multiplication))
    }

    if (this.options.superscriptTwo !== false) {
      rules.push(superscriptTwo(this.options.superscriptTwo))
    }

    if (this.options.superscriptThree !== false) {
      rules.push(superscriptThree(this.options.superscriptThree))
    }

    if (this.options.oneQuarter !== false) {
      rules.push(oneQuarter(this.options.oneQuarter))
    }

    if (this.options.threeQuarters !== false) {
      rules.push(threeQuarters(this.options.threeQuarters))
    }

    return rules
  },
})
